Technical Q&A QA1197
Mapping kernel memory to user space on Mac OS X 10.2


Q: My I/O Kit kernel driver allocates memory that I later map to user space using IOMemoryDescriptor::map. This worked fine on earlier versions of Mac OS X, but on 10.2 map returns NULL. What changed and how do I work around this?

A: IOMemoryDescriptor::map returns NULL because the buffer could not be mapped as requested.

Here’s some background on why this was changed in Mac OS X 10.2. I/O Kit uses the kernel zalloc pool as its small malloc resource. This gives driver writers fast allocations for local use. This is very important for new operators and extremely short lived buffers. The problem arises when a driver writer tries to share this memory with user space, forgetting that the zone allocator is designed for temporary and very private allocations.

Under the covers, I/O Kit allocators such as IOMalloc, IOMallocAligned, and IOMallocContiguous may use this zone allocator to improve the performance of frequent, small allocations. However, if you request at least one full page from IOMallocAligned or IOMallocContiguous, either of these interfaces will return a buffer capable of being shared. The size of a page should not be hard-coded: use the kernel global variable page_size instead. Do not use IOMalloc to acquire memory you ultimately intend to share.

An even nicer change is to allocate buffers and memory descriptors together with IOBufferMemoryDescriptor, which handles the buffer allocation for you as shown in Listing 1.


 memDesc = IOBufferMemoryDescriptor::withOptions(
              kIODirectionOutIn | kIOMemoryKernelUserShared,
              alloc_bytes, page_size );

Listing 1. Use of IOBufferMemoryDescriptor


Once you’ve allocated your buffer using one of these recommended techniques, it can be shared with user space using IOMemoryDescriptor::map.


[Sep 13 2002]


Developer Documentation | Technical Notes | Development Kits | Sample Code